package com.iteaj.iboot.module.iot.collect;

import com.iteaj.framework.exception.ServiceNRBException;
import com.iteaj.iboot.module.iot.collect.action.CollectAction;
import com.iteaj.iboot.module.iot.collect.messageParsing.analyticRule;
import com.iteaj.iboot.module.iot.collect.messageParsing.modbus.ModbusCommandHelper;
import com.iteaj.iboot.module.iot.collect.messageParsing.modbus.ModbusRtuHelper;
import com.iteaj.iboot.module.iot.collect.messageParsing.modbus.parse.ModbusTool;
import com.iteaj.iboot.module.iot.collect.store.StoreAction;
import com.iteaj.iboot.module.iot.collect.store.StoreActionFactory;
import com.iteaj.iboot.module.iot.dto.CollectTaskDto;
import com.iteaj.iboot.module.iot.entity.CollectData;
import com.iteaj.iboot.module.iot.entity.CollectDetail;
import com.iteaj.iboot.module.iot.entity.Signal;
import com.iteaj.iboot.module.iot.mapper.AnalyticRuleMapper;
import com.iteaj.iot.utils.UniqueIdGen;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Data
public class CollectActionTask implements Runnable {

    private CollectTaskDto taskDto;
    private AnalyticRuleMapper analyticRuleMapper;
    private Logger logger = LoggerFactory.getLogger("IOT:DATA:COLLECT");

    public CollectActionTask(CollectTaskDto taskDto) {
        this.taskDto = taskDto;
    }
    public CollectActionTask(CollectTaskDto taskDto,
                             AnalyticRuleMapper analyticRuleMapper) {
        this.taskDto = taskDto;
        this.analyticRuleMapper=analyticRuleMapper;
    }

    @Override
    public void run() {
        if(taskDto != null && !CollectionUtils.isEmpty(taskDto.getDetails())) {
            Date date = new Date(); // 任务开始时间
            long cid = UniqueIdGen.nextLong();
            taskDto.getDetails().forEach(item -> {
                List<CollectData> values = new ArrayList<>();
                CollectAction action = CollectActionFactory.getInstance().get(item.getCollectAction());
                if(action != null) {
                    item.getSignals().forEach(signal -> {
                        CollectData data = new CollectData()
                                .setCid(cid).setReason("")
                                .setStatus(false).setCreateTime(date)
                                .setUid(item.getUid()).setSignalId(signal.getId())
                                .setCollectTaskId(taskDto.getId());
                        try {
                            data.setAddress(signal.getRegistersAddress());
                            data.setFieldType(signal.getFieldType());

                            action.exec(taskDto, item, signal, value -> {
                                // 设置采集的值和采集时间
                                data.setValue(value).setCollectTime(new Date()).setStatus(true);
                            });
                        } catch (CollectException e) {
                            data.setStatus(false).setCollectTime(new Date()).setReason(e.getMessage());
                            logger.error("采集任务失败 接口调用异常 - 任务: {} - 周期: {} - 设备: {}({}) - 点位: {}({})"
                                    , e.getMessage(), taskDto.getName(), taskDto.getCron()
                                    , item.getDevice().getName(), item.getDevice().getUid()
                                    , signal.getName(), signal.getRegistersAddress(), e);
                        } catch (Exception e) {
                            data.setStatus(false).setCollectTime(new Date()).setReason("未知错误");
                            logger.error("采集任务失败 接口调用异常 - 任务: {} - 周期: {} - 设备: {}({}) - 点位: {}({})"
                                    , e.getMessage(), taskDto.getName(), taskDto.getCron()
                                    , item.getDevice().getName(), item.getDevice().getUid()
                                    , signal.getName(), signal.getRegistersAddress(), e);
                        }

                        values.add(data);
                        int type;
                        String message=data.getValue();
                        byte[] msg= ModbusTool.hexString2ByteArray(message);
                        System.out.println("报文"+message);

                        //数据解析
                        Object d = null;

                        //1.CRC检验码检验
                        int var = msg[2];
                        String s = signal.getMessage();
                        String crcValue = message.substring((3+var*2)*2);
                        String validateMsg= s.substring(0, 12)+"0000";
                        boolean result = ModbusRtuHelper.validateCRC(validateMsg, 0, 16, crcValue);
                        if(result == false){
                            throw new SecurityException("CRC校验码错误！");
                        }

                        //2.数据的解析(功能码，数据类型）
                        int commFunction = msg[1];
                        type = signal.getTypeOptions();
                        analyticRule.FliterType fliterType = signal.getType(type);
                        int deviceStation = signal.getDeviceStation();
                        int registersIndex = signal.getRegistersIndex();
                        switch (commFunction){
                            case 1:
                                d = ModbusCommandHelper.getFunction01(deviceStation, registersIndex, msg);
                                break;
                            case 2:
                                d = ModbusCommandHelper.getFunction02(deviceStation, registersIndex, msg);
                                break;
                            case 3:
                                d = ModbusCommandHelper.analyticCommFunction3(fliterType,deviceStation,registersIndex,msg);
                                break;
                            case 4:
                                d = ModbusCommandHelper.analyticCommFunction4(fliterType,deviceStation,registersIndex,msg);
                                break;
                            case 5:
                            case 6:
                                break;
                            default:
                                throw new ServiceNRBException("功能码异常");
                        }

                        //3.数据处理
                        int baseNumber = signal.getBaseNumber();
                        int multiple = signal.getMultiple();
                        boolean absolute = signal.isAbsolute();
                        boolean coefficient = signal.isCoefficient();
                        if(absolute == true){
                            //绝对数
                            data.setValue(String.valueOf(d));
                        } else if (coefficient == true) {
                            //系数
                            double dt = (double)d * baseNumber *multiple;
                            data.setValue(String.valueOf(dt));
                        }

                    });
                }
                    // 存储
                    if (!CollectionUtils.isEmpty(values)) {
                        StoreAction storeAction = StoreActionFactory.getInstance().get(item.getStoreAction());
                        if (storeAction != null) {
                            storeAction.store(item, values);
                        }
                    }
            });
        } else {
            logger.error("采集任务失败 任务不存在");
        }

    }
}
